﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Silverlight.Testing;
using Microsoft.Silverlight.Testing.Harness;
using Microsoft.Silverlight.Testing.UnitTesting.Metadata;
using Microsoft.Silverlight.Testing.UnitTesting.Metadata.NUnit;
using NUnitTestRunnerWP7.ViewModels;

namespace NUnitTestRunnerWP7
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();
            // We're using the Microsoft Unit Tests Runner for silverlight, we need to register the NUnitProvider so NUnit Test can be loaded
            UnitTestSystem.RegisterUnitTestProvider(new NUnitProvider());
        }

        private void btnRun_Click(object sender, RoutedEventArgs e)
        {

            var settings = UnitTestSystem.CreateDefaultSettings();

            settings.TestAssemblies.AddRange(NUnitTestRunner.TestsAssemblies);
            settings.TestHarness.Settings = settings;
            settings.TestHarness.TestHarnessCompleted += TestHarness_TestHarnessCompleted;
            settings.TestHarness.TestMethodCompleted += TestHarness_TestMethodCompleted;

            ResultsListViewModel.Intance.Items.Clear();
            settings.TestHarness.Initialize();
            settings.TestHarness.Run();
        }

        void TestHarness_TestMethodCompleted(object sender, TestMethodCompletedEventArgs e)
        {
            var model = new UnitTestResultViewModel
            {
                ClassName = e.Result.TestClass.Name,
                ElapsedMilliseconds =
                    (int)(e.Result.Finished - e.Result.Started).TotalMilliseconds,
                ErrorMessage =
                    e.Result.Exception == null
                        ? string.Empty
                        : e.Result.Exception.Message.Trim() + "\n\rStack Trace:\n\r" + FilterStackTrace(e.Result.Exception.StackTrace),
                MethodName = e.Result.TestMethod.Name
            };
            
            switch (e.Result.Result)
            {
                case TestOutcome.Failed:
                    model.Result = TestResult.Failed;
                    break;
                case TestOutcome.Passed:
                    model.Result = TestResult.Passed;
                    break;
                case TestOutcome.NotExecuted:
                    model.Result = TestResult.Ignored;
                    break;
            }
            ResultsListViewModel.Intance.Items.Add(model);
        }

        private string FilterStackTrace(string stackTrace)
        {
            int i = stackTrace.IndexOf("\r\n   at System.Reflection.RuntimeMethodInfo.InternalInvoke(RuntimeMethodInfo rtmi, Object obj, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess, StackCrawlMark& stackMark)");
            if (i >= 0)
            {
                return stackTrace.Substring(0, i);
            }
            return stackTrace;
        }

        void TestHarness_TestHarnessCompleted(object sender, TestHarnessCompletedEventArgs e)
        {
            var harness = sender as UnitTestHarness;
            // Including Ignored Tests
            incorporateIgnoredTests(harness);
            // Go to results page
            NavigationService.Navigate(new Uri("/NUnitTestRunnerWP7;component/UnitTestsListPage.xaml", UriKind.Relative));
        }

        void incorporateIgnoredTests(UnitTestHarness harness)
        {
            // Getting the NUnit Tests assembly
            foreach (Assembly assembly in NUnitTestRunner.TestsAssemblies)
            {
                UnitTestFrameworkAssembly testAssembly = new UnitTestFrameworkAssembly(new NUnitProvider(), harness,
                    assembly);
                // Getting the test classes
                var classes = testAssembly.GetTestClasses();
                // Looking for Ignored Tests

                foreach (var testClass in classes)
                {
                    var testMethods = new List<ITestMethod>(testClass.GetTestMethods());
                    if (!testClass.Ignore)
                    {
                        testMethods = testMethods.Where(t => t.Ignore).ToList();
                    }
                    else // TestFixture with Ignore Attribute
                    {
                        // Making all the available tests as ignored
                    }

                    foreach (var testMethod in testMethods)
                    {
                        UnitTestResultViewModel testViewModel = new UnitTestResultViewModel
                        {
                            ClassName = testClass.Name,
                            ElapsedMilliseconds = 0,
                            ErrorMessage = string.Empty,
                            MethodName = testMethod.Name,
                            Result = TestResult.Ignored
                        };
                        ResultsListViewModel.Intance.Items.Add(testViewModel);
                    }
                }
            }
        }
    }
}